package com.manli.api.controller.wechat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.manli.api.base.annotation.Permissions;
import com.manli.api.base.config.JwtAuthTokenTimeConfig;
import com.manli.api.base.exception.MyException;
import com.manli.api.dto.SysWechatConfig;
import com.manli.api.enums.ResultEnums;
import com.manli.api.pojo.QueryParamsRefreshToken;
import com.manli.api.pojo.QueryParamsWechatMiniProgramAuth;
import com.manli.api.pojo.Result;
import com.manli.api.pojo.SessionInfo;
import com.manli.api.service.WechatService;
import com.manli.api.util.JwtUtils;
import com.manli.api.util.ResultUtil;
import com.manli.api.util.WeChatConfigUtil;
import com.manli.api.util.WeChatOverUtil;
import com.manli.common.utils.HttpClientUtils;
import com.manli.common.utils.RandomUtils;
import com.manli.wechat.miniprogram.WechatMiniProgramUtils;
import com.manli.wechat.pojo.*;
import com.manli.wechat.utils.WeChat;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
@Api(tags = "微信小程序模块")
@RequestMapping("api/wechatMiniProgram")
public class WechatMiniProgramController {
	
	Logger logger = LoggerFactory.getLogger(getClass());


	@Autowired
	WechatService wechatService;
	
	@Autowired
	WeChatConfigUtil weChatConfigUtil;
	
	@Autowired
	WeChatOverUtil weChatOverUtil;

	@Autowired
	RedisTemplate redisTemplate;

	
	@ApiOperation(value="微信小程序开发", notes="获取网页授权来的code")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping(value="/getCodeFromWechatAuth")
	public @ResponseBody Result getCodeFromWechatAuth(@RequestBody QueryParamsWechatMiniProgramAuth miniProgramAuth) throws Exception {
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid("wx68b41af749849d4e");
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		//weChatOverUtil.getAccessToken()
		WechatMiniAutoCode2Session authPojo = WechatMiniProgramUtils.getMiniProgramOpenidAndunionId(config.getAppId(), config.getAppSecret(), miniProgramAuth.getCode());
		String sessionKey = null;
		if (miniProgramAuth.isSessionKeyIsOk()){
			sessionKey = (String)redisTemplate.opsForValue().get("WechatSessionKey:"+authPojo.getOpenid());
		}else{
			sessionKey = authPojo.getSession_key();
			redisTemplate.opsForValue().set("WechatSessionKey:"+authPojo.getOpenid(),sessionKey);
		}
		//解密微信小程序
		JSONObject miniProgram = WechatMiniProgramUtils.getUserInfo(miniProgramAuth.getEncryptedData(),sessionKey,miniProgramAuth.getIv());
		if (miniProgram == null){
			throw new MyException(ResultEnums.ERROR_MINIPROGRAM_GETUSERINFO);
		}
		String userInfo = miniProgram.toJSONString();

		WeChatMiniProgramUserInfo miniProgramUserInfo = JSON.parseObject(userInfo, WeChatMiniProgramUserInfo.class);
		if (authPojo == null || "1".equals(authPojo.getErrcode())){
			throw new MyException(ResultEnums.UNKNOW_WECHAT_USER_INFO);
		}
		//用户信息写入数据库
        WeChatUserInfo retWeChatUserInfo = wechatService.saveUpdateWeChatMiniProgramUserInfo(authPojo,miniProgramUserInfo);
		//设置token或则session
		Map<String,Object> claims = new HashMap<String, Object>();
		claims.put("openid", retWeChatUserInfo.getOpenid());
		claims.put("unionid", retWeChatUserInfo.getUnionid());
		String auth_token_wechat = JwtUtils.createJWT(claims, JwtAuthTokenTimeConfig.JwtAuthTokenWechatExpireTime);
		/**
		 * 增加refresh_token用于token过期续期
		 */
		claims.put("randomNum", RandomUtils.getRandNumByLength(10));
		String refresh_token_wechat = JwtUtils.createJWT(claims, JwtAuthTokenTimeConfig.JwtRefreshTokenWechatExpireTime);
		//返回token或则session
		//sessionInfo存入redis
		SessionInfo sessionInfo = new SessionInfo();
		sessionInfo.setWeChatUserInfo(retWeChatUserInfo);
		redisTemplate.opsForValue().set("auth_token_wechat:"+sessionInfo.getWeChatUserInfo().getOpenid(), sessionInfo,JwtAuthTokenTimeConfig.JwtAuthTokenRedisWechatExpireTime, TimeUnit.SECONDS);
		JSONObject object = new JSONObject();
		object.put("auth_token", auth_token_wechat);
		object.put("refresh_token", refresh_token_wechat);
		object.put("sessionInfo",sessionInfo);
		return ResultUtil.success(object);
	}

	@SuppressWarnings("unchecked")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@PostMapping(value="/wechatForRefreshToken")
	public @ResponseBody Result wechatForRefreshToken(HttpServletRequest request, HttpServletResponse response, @RequestBody QueryParamsRefreshToken refreshToken)throws Exception {
		/**
		 * 判断refresh是否有效
		 * 如果有效怎刷新auth_token ，如果无效就报错 提示refresh_token过期 去登陆
		 */
		Claims claims = JwtUtils.verifyJwt(refreshToken.getRefreshToken());
		if (claims!=null) {
			//有效 怎生产一个新的auto_token refresh_token redis延期
			String openid = claims.get("openid").toString();
			SessionInfo sessionInfo = (SessionInfo) redisTemplate.opsForValue().get("auth_token_wechat:"+openid);

			Map<String,Object> newclaims = new HashMap<String, Object>();
			newclaims.put("openid", sessionInfo.getWeChatUserInfo().getOpenid());
			newclaims.put("unionid", sessionInfo.getWeChatUserInfo().getUnionid());
			String auth_token_wechat = JwtUtils.createJWT(newclaims, JwtAuthTokenTimeConfig.JwtAuthTokenWechatExpireTime);
			newclaims.put("randomNum", RandomUtils.getRandNumByLength(10));
			String refresh_token_wechat = JwtUtils.createJWT(newclaims, JwtAuthTokenTimeConfig.JwtRefreshTokenWechatExpireTime);
			//sessionInfo存入redis
			redisTemplate.opsForValue().set("auth_token_wechat:"+sessionInfo.getWeChatUserInfo().getOpenid(), sessionInfo,JwtAuthTokenTimeConfig.JwtAuthTokenRedisWechatExpireTime,TimeUnit.SECONDS);
			JSONObject object = new JSONObject();
			object.put("auth_token_wechat", auth_token_wechat);
			object.put("refresh_token_wechat", refresh_token_wechat);
			object.put("sessionInfo",sessionInfo);
			return ResultUtil.success(object);
		}else {
			throw new MyException(ResultEnums.NO_LOGIN_REFRESH_TOKEN_IS_EXPIRE);
		}
	}

	/**
	 * 详情看官方文档 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html
	 * 此处以官方接口B为例
	 * 生成小程序码，可接受页面参数较短，生成个数不受限
	 *
	 * param :参数 例如：123    page：需要跳转的页面地址 例如：pages/index
	 */
	@ApiOperation(value="微信小程序", notes="获取带参数二维码")
	@Permissions(module = "", privilege = "", typeOfAccess = Permissions.METHOD_OPEN)
	@RequestMapping("/getQrCode")
	public void smallProgramCode(String param, String page, HttpServletResponse response) {
		OutputStream stream = null;
		try {
			//获取AccessToken
			String accessToken = getAccessToken();
			//设置响应类型
			response.setContentType("image/png");
			String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
			//组装参数
			Map<String, Object> paraMap = new HashMap<>();
			//二维码携带参数 不超过32位 参数类型必须是字符串
			paraMap.put("scene", param);
			//二维码跳转页面
			paraMap.put("page", page);
			//二维码的宽度
			paraMap.put("width", 450);
			//自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调
			paraMap.put("auto_color", false);
			//是否需要透明底色， is_hyaline 为true时，生成透明底色的小程序码
			paraMap.put("is_hyaline", false);
			//执行post 获取数据流
			byte[] result = HttpClientUtils.doImgPost(url, paraMap);
			//输出图片到页面
			response.setContentType("image/jpg");
			stream = response.getOutputStream();
			stream.write(result);
			stream.flush();
			stream.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	/**
	 * 获取ACCESS_TOKEN
	 * 官方文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
	 * <p>
	 * 需要正确的 appid  和 secret  查看自己的微信开放平台
	 */
	public String getAccessToken() throws Exception {
		/*String appid = "wx1316adfe368b0ede";
		String appSecret = "c91207f95a6234dd15f9051b0cd";
		//获取微信ACCESS_TOKEN 的Url
		String accent_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
		String url = accent_token_url.replace("APPID", appid).replace("APPSECRET", appSecret);
		//发送请求
		String result = HttpClientUtils.doGet(url);
		Map<String, Object> resultMap = (Map<String, Object>) JsonUtil.jsonToMap(result);
		System.out.println("access_token------>" + resultMap.get("access_token").toString());
		return resultMap.get("access_token").toString();*/
		SysWechatConfig config = weChatConfigUtil.getWeChatByAppid("wx68b41af749849d4e");
		WeChat weChat = new WeChat(config.getAppId(), config.getAppSecret());
		String accessToken = weChatOverUtil.getAccessToken(weChat);
		return accessToken;
	}
}
